package websocket

import (
	"fmt"
	"net/http"
	"strconv"
	"sync"
	"time"

	"data_service/models"

	"github.com/gorilla/websocket"
	"github.com/zeromicro/go-zero/core/logx"
)

// ServeWS 服务WebSocket连接
func (s *WebSocketServer) ServeWS(w http.ResponseWriter, r *http.Request, userID, roomID, userName string) {
	logx.Infof("[ServeWS] 开始处理WebSocket连接: userID=%s, roomID=%s, userName=%s", userID, roomID, userName)

	// 验证必要参数
	if userID == "" {
		logx.Errorf("[ServeWS] 用户ID为空")
		http.Error(w, "用户ID不能为空", http.StatusBadRequest)
		return
	}

	if userName == "" {
		userName = "用户" + userID
		logx.Infof("[ServeWS] 用户名为空，使用默认名称: %s", userName)
	}

	maxUsers := 10 // 默认最大用户数
	if v := r.URL.Query().Get("max_users"); v != "" {
		if max, err := strconv.Atoi(v); err == nil {
			maxUsers = max
		}
	}

	gameType := r.URL.Query().Get("gameType")
	logx.Infof("[ServeWS] 游戏类型: %s", gameType)

	conn, err := s.upgrader.Upgrade(w, r, nil)
	if err != nil {
		logx.Errorf("[ServeWS] WebSocket连接升级失败: %v", err)
		return
	}

	// 创建客户端
	client := &Client{
		UserID:      userID,
		UserName:    userName,
		Conn:        conn,
		Send:        make(chan []byte, 256),
		mu:          sync.Mutex{},
		sendClosed:  false,
		server:      s,
		isConnected: true,
	}

	// 用户上线 - 更新在线状态
	onlineStatusManager := s.GetOnlineStatusManager()
	if onlineStatusManager != nil {
		onlineStatusManager.UserOnline(userID, userName)

		// 发送好友在线状态列表
		friendsStatus := onlineStatusManager.GetFriendsOnlineStatus(userID)
		if len(friendsStatus) > 0 {
			statusMsg := Message{
				Type:    int(MessageTypeFriendsStatus),
				Content: "", // 清空Content，使用Data字段
				Data:    map[string]interface{}{"friends": friendsStatus},
				Time:    time.Now().Unix(),
			}
			client.Send <- statusMsg.ToJSON()
		}
	}

	// 启动写入goroutine
	go client.WritePump()

	// 检查是否为房间列表连接（没有roomID且没有gameType）
	if roomID == "" && gameType == "" {
		// 这是房间列表连接，只用于接收房间列表更新
		logx.Infof("[ServeWS] 用户 %s(%s) 连接房间列表服务", userName, userID)

		// 将客户端添加到房间列表客户端管理
		s.roomListMu.Lock()
		s.roomListClients[userID] = client
		s.roomListMu.Unlock()

		// 发送当前房间列表
		roomsInfo := s.GetAllRoomsInfo()
		msg := Message{
			Type:    int(MessageTypeRoomListUpdate),
			Content: "", // 清空Content，使用Data字段
			Data:    map[string]interface{}{"rooms": roomsInfo},
			Time:    time.Now().Unix(),
		}
		client.Send <- msg.ToJSON()

		// 启动客户端的读写协程
		go client.WritePump()
		go client.ReadPumpRoomList()
		return
	}

	// 处理房间连接
	var room *Room

	// 确定房间类型
	roomType := "chat"
	if gameType != "" {
		roomType = gameType
	}

	// 处理房间连接
	if roomID != "" {
		// 有roomID：查询数据库，找到就加入，找不到就创建
		var dbRoom models.Room
		if s.db != nil {
			err := s.db.First(&dbRoom, roomID).Error
			if err == nil {
				// 找到房间，从数据库创建WebSocket房间
				room = s.CreateRoomFromDB(&dbRoom)
				logx.Infof("[ServeWS] 加入现有房间 %s (类型: %s)", room.ID, roomType)
			} else {
				// 没找到房间，创建新房间
				roomName := fmt.Sprintf("%s的房间", userName)
				room = s.CreateRoom(roomName, roomType, userID, userName, maxUsers)
				logx.Infof("[ServeWS] 创建新房间 %s (类型: %s)", room.ID, roomType)
			}
		}
	} else {
		// 没有roomID：直接创建新房间
		roomName := fmt.Sprintf("%s的房间", userName)
		room = s.CreateRoom(roomName, roomType, userID, userName, maxUsers)
		logx.Infof("[ServeWS] 创建新房间 %s (类型: %s)", room.ID, roomType)
	}

	// 检查房间是否已满
	room.mu.RLock()
	full := len(room.Clients) >= room.MaxUsers
	room.mu.RUnlock()
	if full {
		_ = conn.WriteMessage(websocket.TextMessage, []byte(`{"type":99,"content":"房间已满"}`))
		conn.Close()
		return
	}

	// 添加客户端到房间
	room.AddClient(client)
	logx.Infof("[ServeWS] 客户端已添加到房间 %s", room.ID)

	// 启动客户端的读写协程
	go client.WritePump()
	go client.ReadPump(room)
	logx.Infof("[ServeWS] 客户端读写协程已启动")

	// 发送欢迎消息到房间
	joinMsg := Message{
		Type:     int(MessageTypeJoin),
		UserID:   userID,
		UserName: userName,
		Content:  fmt.Sprintf("%s 加入了房间", userName),
		Time:     time.Now().Unix(),
	}
	room.Broadcast(joinMsg)
	logx.Infof("[ServeWS] 欢迎消息已广播")

	// 广播房间列表更新
	s.BroadcastRoomListUpdate()
	logx.Infof("[ServeWS] 房间列表更新已广播")

	logx.Infof("[ServeWS] 用户 %s(%s) 成功加入房间 %s (类型: %s)", userName, userID, room.ID, roomType)
}
